package com.google.code.virtualhockey.vhx.util

import java.util.Date
import java.text.{ParsePosition, SimpleDateFormat}
import com.google.gwt.json.client.JSONValue
import scala.collection.TraversableLike

/**
 * Contains language supporting utility functions.
 */
object LangUtils {

  /** The format (as string, suitable e.g. for error messages) to use when converting between strings and dates. */
  lazy val FORMAT_STRING_DATE_CONVERSION_FOR_DISPLAY = "yyyy-MM-ddTHH:mm:ss.SSS"
  
  /** The date format to use when converting between strings and dates. */
  lazy val FORMAT_STRING_DATE_CONVERSION = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS" )
  
  /**
   * Automatically closes a resource when all work has been done with it.
   *
   * @param resource the resource offering a close() method
   * @param action the code that should use the resource
   */
  def withResource[R <: { def close(): Unit }]( resource: R )( action: (R) => Unit ) {
    try {
      action( resource )
    }
    finally {
      resource.close()
    }
  }

  /**
   * Converts the given string into a date. The string is expected to conform to the format
   * 'yyyy-MM-dd'T'HH:mm:ss.SSS'.
   *
   * @param str the String to be converted into a Date
   */
  def stringToDate( str: String ): Option[Date] =
    if ( str == null )
      None
    else
      Option( FORMAT_STRING_DATE_CONVERSION.parse( str, new ParsePosition( 0 ) ) )

  /**
   * Converts the given date into a string in the format 'yyyy-MM-dd'T'HH:mm:ss.SSS'.
   *
   * @param date the Date to be converted into a String
   */
  def dateToString( date: Date ): Option[String] =
    if ( date == null )
      None
    else
      Option( FORMAT_STRING_DATE_CONVERSION.format( date ) )

  /**
   * Creates a JSON attribute string.
   *
   * @param name the attribute name
   * @param value the attribute's value
   * @return a JSON compatible attribute string (e.g. <code>"myAttribute":"myStringValue"</code>)
   */
  def toJsonAttribute( name: String, value: Any ): String = {
    val sb = new StringBuilder()

    sb.append( "\"" ).append( name ).append( "\"" ).append( ":" )
    sb.append( toJsonValue( value ) )

    sb.toString()
  }

  /**
   * Converts the given Scala value into a string that is usable within a JSON attribute expression.
   * Supports all derivatives of AnyVal, Option, String, Array and Traversable.
   *
   * @param value the value to be converted
   * @return the value mapped into a JSON compatible value string
   */
  protected def toJsonValue( value: Any ): String = value match {
    case None | null => "null"
    case Unit => sys.error( "Unit is not a supported JSON attribute type." )
    case o: Option[_] => toJsonValue( o.get )
    case n: Byte => n.toString
    case n: Short => n.toString
    case n: Int => n.toString
    case n: Long => n.toString
    case n: Float => n.toString
    case n: Double => n.toString
    case b: Boolean => b.toString
    case s: String => "\"" + s + "\""
    case a: Array[_] => a.map( toJsonValue( _ ) ).mkString( "[", ",", "]" )
    case t: Traversable[_] => t.map( toJsonValue( _ ) ).mkString( "[", ",", "]" )
    case r: AnyRef => sys.error( r.getClass.getName + " is not a supported JSON attribute type." )
  }
}
